# -*- coding: utf-8 -*-
# @Author	: starview.guojian.ma
# @Date		: 2021/11/22 11:08
# @Last Modified by:   starview.guojian.ma
# @Last Modified time: 2021/11/22 11:08
# Thanks for your comments!

import logging
from functools import partial
from typing import Callable
import json
import uuid
from datetime import datetime

from rabbitmq_request_response.amqplib import RabbitMQFactory
from src.config import CONF

from src.basedata.infrastructure.utils.message import JsonCustomEncoder
from src.basedata.infrastructure.utils.context import context_request_id
from src.basedata.interfaces.assembler.request_param import handle_common
from src.seedwork.application.responses import Response, ExceptionResponse

logger = logging.getLogger(__name__)


def init_consumer(register: Callable, publisher: Callable, bus):
    mq_config = CONF.mq_config.get("sync", {})

    # @tornado.gen.coroutine  # lycium中对rabbitmq的调用做了判断，只有是tornado.gen.coroutine才可以
    async def handle(channel, method, properties, body):
        exception_resp = ExceptionResponse()
        logger.info("received a message by routing_key:%s data: %r", method.routing_key, str(body))
        try:
            payload = json.loads(body)
        except Exception as e:
            logger.error(f'deserialization failed with err:{str(e)}')
            exception_resp.message = f"数据JSON解析失败:{str(e)}"
            return exception_resp

        request_id = payload.get("requestId", "")
        if request_id == "":
            request_id = str(uuid.uuid4()).replace('-', '')
            payload["request_id"] = request_id
        logger.info(f"set request_id:{request_id} for log print")
        context_request_id.set(request_id)
        start = datetime.now()
        try:
            result = await handle_common(payload, bus)
            if not result:
                exception_resp.message = "请求没有返回"
                return exception_resp

            if isinstance(result, Response):
                result = result.serialize_to_dict()
            end = datetime.now()
            logger.info(f'handle result spent time:{(end - start).microseconds}')
            result['bizCode'] = payload.get('bizCode')
            result['requestId'] = payload.get('requestId', '')

            serialize_result = json.dumps(result, cls=JsonCustomEncoder, ensure_ascii=False)
            logger.info(f'final result:{serialize_result}')
            return serialize_result
        except Exception as e:
            from traceback import format_exc
            logger.error(f'handle result failed with err:{str(e)}\n{format_exc()}')
            exception_resp.message = f"请求处理异常:{str(e)}"
            return exception_resp

    register(exchange=mq_config['exchange']['name'],
             exchange_type=mq_config['exchange']['type'],
             binding_key=mq_config['binding_key'],
             queue=mq_config['queue'],
             durable=mq_config['durable'],
             callback=handle,
             auto_ack=True)
    logger.info(
        f"rabbitmq consumer handle was registered. "
        f"exchange:{mq_config['exchange']['name']}, "
        f"queue:{mq_config['queue']}")


def rabbitmq_main(bus):
    receive_conn = CONF.rabbitmq_xhhk  # 初始化接收来自ws的消息
    factory = RabbitMQFactory()
    factory.initialize({
        'host': receive_conn.get('host'),
        'port': receive_conn.get('port'),
        'username': receive_conn.get('username'),
        'password': receive_conn.get('password'),
        'virtual_host': receive_conn.get('virtual_host'),
        'sock_timeout': receive_conn.get('timeout'),
        'heartbeat': receive_conn.get('heartbeat')
    })
    virtual_host = receive_conn.get('virtual_host', '/')
    logger.info(
        f'rabbitmq was initialized. '
        f'host:{receive_conn.get("host")}, '
        f'port:{receive_conn.get("port")}, '
        f'username:{receive_conn.get("username")}')

    init_consumer(partial(factory.consume, virtual_host),
                  partial(factory.publish, virtual_host),
                  bus)
    factory.run()
